package com.yeskery.nut.core;

import com.yeskery.nut.util.EnvironmentUtils;
import com.yeskery.nut.util.IOUtils;
import com.yeskery.nut.util.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Collections;
import java.util.Set;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 抽象的环境资源对象
 * @author sprout
 * @version 1.0
 * 2022-07-09 11:29
 */
public abstract class AbstractEnvironmentResource implements EnvironmentResource {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(AbstractEnvironmentResource.class.getName());

    /** 换行符 */
    private static final String NEW_LINE = "\r\n";

    /** 环境对象 */
    private final Environment environment;

    /** 资源名称 */
    private final String name;

    /** 资源的缓存 */
    private volatile byte[] resourceCacheBytes;

    /**
     * 构建类路径下的环境资源对象
     * @param environment 环境对象
     * @param name 资源名称
     */
    public AbstractEnvironmentResource(Environment environment, String name) {
        if (environment == null) {
            throw new NutException("Environment Can Not Be Null.");
        }
        this.environment = environment;
        if (StringUtils.isEmpty(name)) {
            throw new NutException("Resource Name Can Not Be Empty.");
        }
        this.name = name;
    }

    @Override
    public InputStream getInputStream() {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getResourceCacheBytes());
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(byteArrayInputStream));
        byte[] bytes = getPlaceHolderContextArray(bufferedReader);
        return new ByteArrayInputStream(bytes);
    }

    @Override
    public Reader getReader() {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getResourceCacheBytes());
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(byteArrayInputStream));
        byte[] bytes = getPlaceHolderContextArray(bufferedReader);
        return new StringReader(new String(bytes, StandardCharsets.UTF_8));
    }

    /**
     * 获取环境对象
     * @return 环境对象
     */
    public Environment getEnvironment() {
        return environment;
    }

    /**
     * 获取资源名称
     * @return 资源名称
     */
    public String getName() {
        return name;
    }

    /**
     * 获取原始输入流
     * @return 原始输入流
     */
    protected abstract InputStream getOriginalInputStream();

    /**
     * 获取占位符处理内容数组
     * @param bufferedReader 缓冲读取Reader
     * @return 占位符处理内容数组
     */
    private byte[] getPlaceHolderContextArray(BufferedReader bufferedReader) {
        try {
            StringBuilder stringBuilder = new StringBuilder();
            Properties envProperties = environment.getEnvProperties();
            String line;

            while ((line = bufferedReader.readLine()) != null) {
                Set<String> placeHolders = EnvironmentUtils.getPlaceHolders(line);
                if (placeHolders.isEmpty()) {
                    stringBuilder.append(line);
                } else {
                    String result = line;
                    for (String placeHolder : placeHolders) {
                        String placeHolderName = placeHolder.substring(2, placeHolder.length() - 1);
                        String value = envProperties.getProperty(placeHolderName);
                        if (value != null) {
                            result = result.replace(placeHolder, value);
                        }
                    }
                    stringBuilder.append(result);
                }
                stringBuilder.append(NEW_LINE);
            }

            if (NEW_LINE.equals(stringBuilder.substring(stringBuilder.length() - NEW_LINE.length()))) {
                stringBuilder.delete(stringBuilder.length() - NEW_LINE.length(), stringBuilder.length());
            }
            return stringBuilder.toString().getBytes(StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new NutException("Environment Resource Read Fail.", e);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    logger.logp(Level.SEVERE, this.getClass().getName(), "getPlaceHolderContextArray",
                            "IO Close Fail.", e);
                }
            }
        }
    }

    /**
     * 获取缓存资源
     * @return 缓存资源
     */
    private byte[] getResourceCacheBytes() {
        if (resourceCacheBytes == null) {
            synchronized (this) {
                if (resourceCacheBytes == null) {
                    InputStream inputStream = getOriginalInputStream();
                    resourceCacheBytes = IOUtils.readByteArray(inputStream);
                }
            }
        }
        return resourceCacheBytes;
    }
}
